package mymail.cryptography.asymmetric;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Date;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class RSA {

    private Key publicKey;
    private Key privateKey;

    public RSA() {
        publicKey = null;
        privateKey = null;
    }

    public Key getPublicKey() {
        return publicKey;
    }

    public void setPublicKey(Key publicKey) {
        this.publicKey = publicKey;
    }

    public Key getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(Key privateKey) {
        this.privateKey = privateKey;
    }

    public String Encrypt(String data) throws Exception {

        if (privateKey == null && publicKey == null) {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(512);

            KeyPair keyPair = keyGen.genKeyPair();
            privateKey = keyPair.getPrivate();
            publicKey = keyPair.getPublic();
        }

        Cipher c = Cipher.getInstance("RSA");
        c.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedValue = c.doFinal(data.getBytes("UTF-8"));
        String encryptedData = new BASE64Encoder().encode(encryptedValue);

        return encryptedData;
    }

    public static String Decrypt(String encryptedData, String privateKeyFilename)
            throws Exception {

        FileInputStream keyfis = new FileInputStream(privateKeyFilename);
        byte[] priBytes = new byte[keyfis.available()];
        keyfis.read(priBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(priBytes);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

        Cipher c = Cipher.getInstance("RSA");

        c.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decryptedValue = c.doFinal(decordedValue);
        String decryptedString = new String(decryptedValue);

        return decryptedString;
    }

    @SuppressWarnings("deprecation")
    public String EncryptFile(String filename) throws Exception {

        if (privateKey == null && publicKey == null) {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(512);

            KeyPair keyPair = keyGen.genKeyPair();
            privateKey = keyPair.getPrivate();
            publicKey = keyPair.getPublic();
        }

        Cipher c = Cipher.getInstance("RSA");
        c.init(Cipher.ENCRYPT_MODE, publicKey);

        FileInputStream fis = new FileInputStream(filename);
        int last = filename.lastIndexOf("/");
        File directory = new File(".");
        String name = directory.getCanonicalPath()
                + "/temp/"
                + (new Date()).toLocaleString().replace(" ", "").replace(":", "").replace(",", "")
                + filename.substring(last);

        File f;
        f = new File(name);
        f.createNewFile();

        FileOutputStream fos = new FileOutputStream(name);
        CipherOutputStream cos = new CipherOutputStream(fos, c);

        byte[] block = new byte[32];
        int i;
        while ((i = fis.read(block)) != -1) {
            cos.write(block, 0, i);
        }
        cos.close();

        return name;
    }

    public static void DecryptFile(String inputFilename, String outputFilename,
            String privateKeyFilename) throws Exception {

        FileInputStream keyfis = new FileInputStream(privateKeyFilename);
        byte[] priBytes = new byte[keyfis.available()];
        keyfis.read(priBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(priBytes);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

        Cipher c = Cipher.getInstance("RSA");

        c.init(Cipher.DECRYPT_MODE, privateKey);

        FileInputStream fis = new FileInputStream(inputFilename);
        CipherInputStream cis = new CipherInputStream(fis, c);
        FileOutputStream fos = new FileOutputStream(outputFilename);

        byte[] block = new byte[32];
        int i;
        while ((i = cis.read(block)) != -1) {
            fos.write(block, 0, i);
        }
        fos.close();

    }
}
